package com.imooc.security.browser.config;

import com.imooc.security.browser.authentication.ImoocAuthenticationFailHandler;
import com.imooc.security.browser.authentication.ImoocAuthenticationSuccessHandler;
import com.imooc.security.core.authentication.mobile.AbstractChannelSecurityConfig;
import com.imooc.security.core.authentication.mobile.SmsCodeAuthenticationSecurityConfigurer;
import com.imooc.security.core.properties.ImoocSecurityConstants;
import com.imooc.security.core.properties.SecurityProperties;
import com.imooc.security.core.validate.code.SmsCodeFilter;
import com.imooc.security.core.validate.code.ValidateCodeFilter;
import com.imooc.security.core.validate.code.ValidateCodeSecurityConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;

/**
 * Author:   yangdc
 * Date:     2018/9/4 23:07
 */
@Component
public class BrowserSecurityConfig extends AbstractChannelSecurityConfig {
    // 用来读取配置
    @Autowired
    private SecurityProperties securityProperties;

    // 登录成功后的处理
    @Autowired
    private ImoocAuthenticationSuccessHandler imoocAuthenticationSuccessHandler;

    // 登录失败后的处理
    @Autowired
    private ImoocAuthenticationFailHandler imoocAuthenticationFailHandler;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private UserDetailsService userDetailsService;

    // 验证码校验的配置
    @Autowired
    private ValidateCodeSecurityConfigurer validateCodeSecurityConfigurer;

    // 短信登录认证的配置
    @Autowired
    private SmsCodeAuthenticationSecurityConfigurer smsCodeAuthenticationSecurityConfigurer;

    // 配置PasswordEncoder
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    // 用于remember me
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        // tokenRepository.setCreateTableOnStartup(true); // 启动时创建表
        return tokenRepository;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        System.out.println("BrowserSecurityConfig");

        applyPasswordAuthenticationConfig(http);

        http.apply(validateCodeSecurityConfigurer) // 验证码的校验配置

                // 短信登录认证的配置
                .and()
                .apply(smsCodeAuthenticationSecurityConfigurer)

                // 记住我的配置
                .and()
                .rememberMe()
                .tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())
                .userDetailsService(userDetailsService)

                // 对需要认证和不需要认证的资源的配置
                .and()
                .authorizeRequests() // 对请求做授权
                .antMatchers(ImoocSecurityConstants.DEFAULT_UNAUTHENTICATION_URL,
                        ImoocSecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_MOBILE,
                        securityProperties.getBrowser().getLoginPage(),
                        ImoocSecurityConstants.DEFAULT_VALIDATE_CODE_URL_PREFIX + "/*",
                        "/index.html",
                        "/")
                    .permitAll() // 不需要认证的页面
                .anyRequest() // 任何请求
                .authenticated() // 都需要身份认证

                // 暂时将防护跨站请求伪造的功能置为不可用
                .and()
                .csrf().disable();
    }
}
